package com.hopes.common.receive.aspect;

import com.alibaba.fastjson.JSON;
import com.hopes.boss.admin.api.dto.SysLogDTO;
import com.hopes.boss.common.core.constant.CommonConstants;
import com.hopes.boss.common.data.tenant.TenantContextHolder;
import com.hopes.boss.common.log.util.LogTypeEnum;
import com.hopes.boss.common.log.util.SysLogUtils;
import com.hopes.common.receive.annotation.RecordLog;
import com.hopes.common.receive.enums.DataTypeEnum;
import com.hopes.common.receive.event.ReceiveLogEvent;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.web.servlet.mvc.method.annotation.ExtendedServletRequestDataBinder;

import javax.servlet.http.HttpServletResponseWrapper;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Slf4j
@Aspect
@RequiredArgsConstructor
public class RecordLogAspect {

    private final ApplicationEventPublisher publisher;

    @SneakyThrows
    @Around("@annotation(recordLog)")
    public Object around(ProceedingJoinPoint point, RecordLog recordLog) {
        String className = point.getTarget().getClass().getName();
        String methodName = point.getSignature().getName();
        log.debug("[类名]:{},[方法]:{}", className, methodName);

        Object[] args = point.getArgs();
        String[] parameterNames = ((MethodSignature) point.getSignature()).getParameterNames();

        final Map<String, Object> paramMap = new HashMap<>();
        for (int i = 0; i < args.length; i++) {
            if (args[i] instanceof ExtendedServletRequestDataBinder && args[i] instanceof HttpServletResponseWrapper) {
                continue;
            }
            paramMap.put(parameterNames[i], args[i]);
        }

        SysLogDTO sysLog = SysLogUtils.getSysLog();
        sysLog.setTitle(recordLog.value());
        sysLog.setParams(JSON.toJSONString(paramMap));
        // 发送异步日志事件
        Long startTime = System.currentTimeMillis();
        Object obj;
        try {
            obj = point.proceed();
        } catch (Exception e) {
            sysLog.setLogType(LogTypeEnum.ERROR.getType());
            sysLog.setException(e.getMessage());
            throw e;
        } finally {
            Long endTime = System.currentTimeMillis();
            sysLog.setTime(endTime - startTime);
            sysLog.setTenantId(
                    Optional.ofNullable(TenantContextHolder.getTenantId()).orElse(CommonConstants.TENANT_ID_1));
            publisher.publishEvent(new ReceiveLogEvent(this, sysLog, DataTypeEnum.findByName(recordLog.type())));
        }
        return obj;
    }

}
